package com.onluy.frameworkcloud.tools.utils;


import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;

 
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.google.zxing.qrcode.encoder.QRCode;
import com.onluy.frameworkcloud.Constant.SystemConstant;
  

public class CodeUtils {  
	private static final int QRCOLOR = 0xFF000000;   //默认是黑色
    private static final int BGWHITE = 0xFFFFFFFF;   //背景颜色
    private static final String EXT = "png";		 //二维码格式
    private static final int SCIMAGEWIDTH = 400;	 //二维码宽度
    private static final int SCIMAGEHEIGHT = 400;	 //二维码高度
    private static final int QTIMAGEWIDTH = 80;		 //嵌套图片宽度
    private static final int QTIMAGEHEIGHT = 80;	 //嵌套图片高度
    private static int MARGIN = 1;               	 //白边大小，取值范围0~4  
    private static ErrorCorrectionLevel LEVEL = ErrorCorrectionLevel.H;  //二维码容错率  
    
    // 二维码写码器  
    private static MultiFormatWriter mutiWriter = new MultiFormatWriter();  
    /**
     * @author chenzheng
     * @date 2017-06-19
     * 生成带嵌套图片的二维码
     * 
     * @param url 二维码内容
     * @param ext 生成二维码图片格式
     * @param srcImagePath 生成二维码图片路径（不含格式）
     * @param scImageWidth 生成二维码图片宽度
     * @param scImageHeight 生成二维码图片高度
     * @param destImagePath 嵌套图片路径
     * @param qtImageWidth 嵌套图片宽度
     * @param qtImageHeight 嵌套图片高度
     */ 
    public static void encode(String url,String ext,String srcImagePath, int scImageWidth, int scImageHeight, String destImagePath,int qtImageWidth,int qtImageHeight) {  
        try {  
        	
        	if(ext == null || "".equals(ext) || "null".equals(ext)){
        		ext = EXT;
        	}
        	if(scImageWidth == 0 || "".equals(scImageWidth) || "null".equals(scImageWidth)){
        		scImageWidth = SCIMAGEWIDTH;
        	}
        	if(scImageHeight == 0 || "".equals(scImageHeight) || "null".equals(scImageHeight)){
        		scImageHeight = SCIMAGEHEIGHT;
        	}
        	if(qtImageWidth == 0 || "".equals(qtImageWidth) || "null".equals(qtImageWidth)){
        		qtImageWidth = QTIMAGEWIDTH;
        	}
        	if(qtImageHeight == 0 || "".equals(qtImageHeight) || "null".equals(qtImageHeight)){
        		qtImageHeight = QTIMAGEHEIGHT;
        	}
        	
        	
        	//拼凑二维码全路径
        	srcImagePath = srcImagePath +"."+ext;
        	ImageIO.write(genBarcode(url, scImageWidth, scImageHeight, destImagePath,qtImageWidth,qtImageHeight),ext, new File(srcImagePath));         
        	
        } catch (IOException e) {  
            e.printStackTrace();  
        } catch (WriterException e) {  
            e.printStackTrace();  
        }  
    }  
    
    /**
     * @author chenzheng
     * @date 2017-06-19
     * 生成普通的二维码
     * 
     * @param url 二维码内容
     * @param ext 生成二维码图片格式
     * @param srcImagePath 生成二维码图片路径（不含格式）
     * @param scImageWidth 生成二维码图片宽度
     * @param scImageHeight 生成二维码图片高度
     */ 
    public static void encodeByQtImg(String url,String ext,String srcImagePath, int scImageWidth, int scImageHeight) {  
        try {  
        	
        	if(ext == null || "".equals(ext) || "null".equals(ext)){
        		ext = EXT;
        	}
        	if(scImageWidth == 0 || "".equals(scImageWidth) || "null".equals(scImageWidth)){
        		scImageWidth = SCIMAGEWIDTH;
        	}
        	if(scImageHeight == 0 || "".equals(scImageHeight) || "null".equals(scImageHeight)){
        		scImageHeight = SCIMAGEHEIGHT;
        	}
        	//拼凑二维码全路径
        	srcImagePath = srcImagePath +"."+ext;
        	ImageIO.write(genBarcodeByQtImg(url, scImageWidth, scImageHeight),ext, new File(srcImagePath));         	         
        } catch (IOException e) {  
            e.printStackTrace();  
        } catch (WriterException e) {  
            e.printStackTrace();  
        }  
    }  
    
    /**
     * 普通二维码生成
     * @param url
     * @param scImageWidth
     * @param scImageHeight
     * @return
     * @throws WriterException
     * @throws IOException
     */
	private static BufferedImage genBarcodeByQtImg(String url, int scImageWidth,int scImageHeight) throws WriterException,IOException {  
	
		Map<EncodeHintType, Object> hint = new HashMap<EncodeHintType, Object>();  
		hint.put(EncodeHintType.CHARACTER_SET, "utf-8");  
		hint.put(EncodeHintType.ERROR_CORRECTION, LEVEL);  
		hint.put(EncodeHintType.MARGIN, MARGIN);
		// 生成二维码  
		QRCode qrcodeHandler = new QRCode();
		BitMatrix matrix = mutiWriter.encode(url, BarcodeFormat.QR_CODE,scImageWidth, scImageHeight, hint);  
		
		int width = matrix.getWidth();
	    int height = matrix.getHeight();
	    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
	    for (int x = 0; x < width; x++) {
	      for (int y = 0; y < height; y++) {
	        image.setRGB(x, y, matrix.get(x, y) ? QRCOLOR : BGWHITE);
	      }
	    }
	
		return image;  
	}  
    /**
     * 嵌套图片二维码生成
     * @param url
     * @param scImageWidth
     * @param scImageHeight
     * @param destImagePath
     * @param qtImageWidth
     * @param qtImageHeight
     * @return
     * @throws WriterException
     * @throws IOException
     */
    private static BufferedImage genBarcode(String url, int scImageWidth,int scImageHeight, String destImagePath,int qtImageWidth,int qtImageHeight) throws WriterException,  
            IOException {  
        // 读取源图像  
        BufferedImage scaleImage = scale(destImagePath, qtImageWidth,qtImageHeight, true);  
        int[][] srcPixels = new int[qtImageWidth][qtImageHeight];  
        for (int i = 0; i < scaleImage.getWidth(); i++) {  
            for (int j = 0; j < scaleImage.getHeight(); j++) {  
                srcPixels[i][j] = scaleImage.getRGB(i, j);  
            }  
        }  
  
        Map<EncodeHintType, Object> hint = new HashMap<EncodeHintType, Object>();  
        hint.put(EncodeHintType.CHARACTER_SET, "utf-8");  
        hint.put(EncodeHintType.ERROR_CORRECTION, LEVEL);  
        hint.put(EncodeHintType.MARGIN, MARGIN);
        // 生成二维码  
        BitMatrix matrix = mutiWriter.encode(url, BarcodeFormat.QR_CODE, scImageWidth, scImageHeight, hint);  
  
        // 二维矩阵转为一维像素数组  
        int halfW = matrix.getWidth() / 2;  
        int halfH = matrix.getHeight() / 2;  
        int[] pixels = new int[scImageWidth * scImageHeight];  
        int imageHalfWidth = qtImageWidth/2;
        int frameWidth = 2;
        for (int y = 0; y < matrix.getHeight(); y++) {  
            for (int x = 0; x < matrix.getWidth(); x++) {  
                // 读取图片  
                if (x > halfW - imageHalfWidth  
                        && x < halfW + imageHalfWidth  
                        && y > halfH - imageHalfWidth  
                        && y < halfH + imageHalfWidth) {  
                    pixels[y * scImageWidth + x] = srcPixels[x - halfW  
                            + imageHalfWidth][y - halfH + imageHalfWidth];  
                }   
                // 在图片四周形成边框  
                else if ((x > halfW - imageHalfWidth - frameWidth  
                        && x < halfW - imageHalfWidth + frameWidth  
                        && y > halfH - imageHalfWidth - frameWidth && y < halfH  
                        + imageHalfWidth + frameWidth)  
                        || (x > halfW + imageHalfWidth - frameWidth  
                                && x < halfW + imageHalfWidth + frameWidth  
                                && y > halfH - imageHalfWidth - frameWidth && y < halfH  
                                + imageHalfWidth + frameWidth)  
                        || (x > halfW - imageHalfWidth - frameWidth  
                                && x < halfW + imageHalfWidth + frameWidth  
                                && y > halfH - imageHalfWidth - frameWidth && y < halfH  
                                - imageHalfWidth + frameWidth)  
                        || (x > halfW - imageHalfWidth - frameWidth  
                                && x < halfW + imageHalfWidth + frameWidth  
                                && y > halfH + imageHalfWidth - frameWidth && y < halfH  
                                + imageHalfWidth + frameWidth)) {  
                    pixels[y * scImageWidth + x] = 0xfffffff;  
                } else {  
                    // 此处可以修改二维码的颜色，可以分别制定二维码和背景的颜色；  
                    pixels[y * scImageWidth + x] = matrix.get(x, y) ? QRCOLOR : BGWHITE;  
                }  
            }  
        }  
  
        BufferedImage image = new BufferedImage(scImageWidth, scImageHeight, BufferedImage.TYPE_INT_RGB);  
        image.getRaster().setDataElements(0, 0, scImageWidth, scImageHeight, pixels);  
        scaleImage.flush();
        return image;  
    }  
  
    /** 
     * 把传入的原始图像按高度和宽度进行缩放，生成符合要求的图标 
     *  
     * @param srcImageFile 
     *            源文件地址 
     * @param height 
     *            目标高度 
     * @param width 
     *            目标宽度 
     * @param hasFiller 
     *            比例不对时是否需要补白：true为补白; false为不补白; 
     * @throws IOException 
     */  
    private static BufferedImage scale(String srcImageFile, int qtImageWidth,  
            int qtImageHeight, boolean hasFiller) throws IOException {  
        double ratio = 0.0; // 缩放比例  
        File file = new File(srcImageFile);  
        BufferedImage srcImage = ImageIO.read(file);  
        Image destImage = srcImage.getScaledInstance(qtImageWidth, qtImageHeight,  
                BufferedImage.SCALE_SMOOTH);  
        // 计算比例  
        if ((srcImage.getHeight() > qtImageHeight) || (srcImage.getWidth() > qtImageWidth)) {  
            if (srcImage.getHeight() > srcImage.getWidth()) {  
                ratio = (new Integer(qtImageHeight)).doubleValue()  
                        / srcImage.getHeight();  
            } else {  
                ratio = (new Integer(qtImageWidth)).doubleValue()  
                        / srcImage.getWidth();  
            }  
            AffineTransformOp op = new AffineTransformOp(  
                    AffineTransform.getScaleInstance(ratio, ratio), null);  
            destImage = op.filter(srcImage, null);  
        }  
        if (hasFiller) {// 补白  
            BufferedImage image = new BufferedImage(qtImageWidth, qtImageHeight,  
                    BufferedImage.TYPE_INT_RGB);  
            Graphics2D graphic = image.createGraphics();  
            graphic.setColor(Color.white);  
            graphic.fillRect(0, 0, qtImageWidth, qtImageHeight);  
            if (qtImageWidth == destImage.getWidth(null))  
                graphic.drawImage(destImage, 0,  
                        (qtImageHeight - destImage.getHeight(null)) / 2,  
                        destImage.getWidth(null), destImage.getHeight(null),  
                        Color.white, null);  
            else  
                graphic.drawImage(destImage,  
                        (qtImageWidth - destImage.getWidth(null)) / 2, 0,  
                        destImage.getWidth(null), destImage.getHeight(null),  
                        Color.white, null);  
            graphic.dispose();  
            destImage = image;  
        }        
        srcImage.flush();
        return (BufferedImage) destImage;  
    }  
    
    
    /**
	* 二维码下载
	* @param filePath 源文件路径
	*/
	public static void download(HttpServletRequest request,HttpServletResponse response, String filePath)throws Exception {
		
		File file = new File(filePath);
		String fileName = file.getName();
		String ext = fileName.substring(fileName.lastIndexOf("."), fileName.length());
		
        //设置文件MIME类型  
        response.setContentType("application/x-download");  
        if(".zip".endsWith(ext)){
        	Date date = new Date();
        	SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");        	
        	fileName = "二维码"+sdf.format(date)+".zip";
        }
        
        String userAgent = request.getHeader("User-Agent");  
        boolean isIE = (userAgent != null) && (userAgent.toLowerCase().indexOf("msie") != -1);  
      
      
        response.reset();  
        response.setHeader("Pragma", "No-cache");  
        response.setHeader("Cache-Control", "must-revalidate, no-transform");  
        response.setDateHeader("Expires", 0L);  
        
        if (isIE) {  
            fileName = URLEncoder.encode(fileName, "UTF-8");  
            response.setHeader("Content-Disposition", "attachment;filename=\"" + fileName + "\"");  
        } else {  
        	fileName = new String(fileName.getBytes("UTF-8"), "ISO8859-1");  
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);  
        }  
        
        //读取目标文件，通过response将目标文件写到客户端  

        byte[] buf = new byte[1024];  
        int len = 0;  
        BufferedInputStream is = null;  
        OutputStream os = null;  
        try {        
            is = new BufferedInputStream(new FileInputStream(file));  
            os = response.getOutputStream();  
            while ((len = is.read(buf)) != -1)  
                os.write(buf, 0, len);  
        } catch (Exception e) {  
            e.printStackTrace();  
        } finally {  
        	//file.delete();
            is.close();  
        }   
        
        file.delete();
	}
	
	// 将GBK字符转化为ISO码
	public static String parseGBK(String sIn) {
		if (sIn == null || sIn.equals(""))
			return sIn;
		try {
			return new String(sIn.getBytes("GBK"), "ISO-8859-1");
		} catch (UnsupportedEncodingException usex) {
			return sIn;
		}
	}
	
	/** 
     * 将存放在sourceFilePath目录下的源文件，打包成fileName名称的zip文件，并存放到zipFilePath路径下 
     * @param sourceFilePath :待压缩的文件路径 
     * @param zipFilePath :压缩后存放路径 
     * @param fileName :压缩后文件的名称 
     * @return 
	 * @throws Exception 
     */  
    public static boolean fileToZip(String sourceFilePath,String zipFilePath,String fileName) throws Exception{  
        boolean flag = false;  
        File sourceFile = new File(sourceFilePath);  
        FileInputStream fis = null;  
        BufferedInputStream bis = null;  
        FileOutputStream fos = null;  
        ZipOutputStream zos = null;  
          
        if(sourceFile.exists() == false){ 
        	throw new Exception("待压缩的文件目录："+sourceFilePath+"不存在."); 
        }else{  
            try {  
                File zipFile = new File(zipFilePath + File.separator + fileName +".zip");  
                if(zipFile.exists()){  
                	throw new Exception(zipFilePath + "目录下存在名字为:" + fileName +".zip" +"打包文件.");
                }else{  
                    File[] sourceFiles = sourceFile.listFiles();  
                    if(null == sourceFiles || sourceFiles.length<1){  
                    	throw new Exception("待压缩的文件目录：" + sourceFilePath + "里面不存在文件，无需压缩.");
                    }else{  
                        fos = new FileOutputStream(zipFile);  
                        zos = new ZipOutputStream(new BufferedOutputStream(fos));  
                        byte[] bufs = new byte[1024*10];  
                        for(int i=0;i<sourceFiles.length;i++){  
                            //创建ZIP实体，并添加进压缩包  
                            ZipEntry zipEntry = new ZipEntry(sourceFiles[i].getName());  
                            zos.putNextEntry(zipEntry);  
                            //读取待压缩的文件并写进压缩包里  
                            fis = new FileInputStream(sourceFiles[i]);  
                            bis = new BufferedInputStream(fis, 1024*10);  
                            int read = 0;  
                            while((read=bis.read(bufs, 0, 1024*10)) != -1){  
                                zos.write(bufs,0,read);  
                            }  
                        }  
                        flag = true;  
                    }  
                }  
            } catch (FileNotFoundException e) {  
                e.printStackTrace();  
                throw new RuntimeException(e);  
            } catch (IOException e) {  
                e.printStackTrace();  
                throw new RuntimeException(e);  
            } finally{  
                //关闭流  
                try {  
                    if(null != bis) bis.close();  
                    if(null != zos) zos.close();  
                } catch (IOException e) {  
                    e.printStackTrace();  
                    throw new RuntimeException(e);  
                }  
            }  
        }  
        return flag;  
    }  
    
    
    /**
     * 删除临时文件夹
     * @param path
     */
    public static void deleteAllFilesOfDir(File path) {  
        if (!path.exists())  
            return;  
        if (path.isFile()) {  
            path.delete();  
            return;  
        }  
        File[] files = path.listFiles();  
        for (int i = 0; i < files.length; i++) {  
            deleteAllFilesOfDir(files[i]);  
        }  
        path.delete();  
    }  
    
  
    public static void main(String[] args) {  
    	//二维码url
    	String url = "http://coolshell.cn/articles/10590.html";
    	//生成二维码图片格式
    	String ext = "jpg";
    	//二维码要嵌套的图片路径    
    	String qtImagePath = "D:\\logo.png";	
    	int qtImageWidth = 80;
    	int qtImageHeight = 80;
    	//所要生成的二维码图片路径(不含格式)
    	String scImagePath = "D:\\333";
    	int scImageWidth = 400;
    	int scImageHeight = 400;
        //CodeUtils.encode(url,ext,scImagePath,scImageWidth, scImageHeight,qtImagePath,qtImageWidth,qtImageHeight); 
    	CodeUtils.encodeByQtImg(url, ext, scImagePath, scImageWidth, scImageHeight);
    	
    	String tdcId = null;
		String newKey = MD5Util.decrypt("YJvAz2", SystemConstant.TDC_KEY);
		System.out.println(newKey);
    }  
}  